/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mygame;

import static mygame.utils.Utils.notNull;
import static mygame.utils.Utils.isNull;

import com.jme3.asset.AssetManager;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.PhysicsTickListener;
import com.jme3.bullet.collision.PhysicsCollisionObject;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.objects.PhysicsGhostObject;
import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh;
import com.jme3.effect.shapes.EmitterSphereShape;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import java.util.Iterator;

/**
 *
 * @author Diego
 */
public class ShootHandler extends RigidBodyControl implements PhysicsCollisionListener, PhysicsTickListener {
    private static final float EXPLOSION_RADIUS = 7f;
    private static final int PARTICLES_NUMBER = 30;
    private static final float START_PARTICLE_SIZE = 1.3f;
    private static final float END_PARTICLE_SIZE = 2.0f;
    private static final float MAXIMUM_TIMER = 4.0f;
    private static final float FIXED_TIME = 0.5f;
    private static final float FORCE_FACTOR = 1.2f;
    private static final float CURRENT_TIME_START = -1.0f;
    
    private ParticleEmitter emitter;
    private AssetManager assetManager;
    private PhysicsGhostObject physicsGhostObject;
    private float timer;
    private float currentTime = CURRENT_TIME_START;
    private Vector3f location = new Vector3f();
    
    public ShootHandler(AssetManager assetManager, CollisionShape shape, float mass) {
        super(shape, mass);
        this.assetManager = assetManager;
        this.physicsGhostObject = new PhysicsGhostObject(new SphereCollisionShape(EXPLOSION_RADIUS));
        setUpEmiiter();
    }
    
    private void setUpEmiiter () {
        emitter = new ParticleEmitter("Shoot", ParticleMesh.Type.Triangle, PARTICLES_NUMBER);
        Material material = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
        material.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/shockwave.png"));
        
        emitter.setSelectRandomImage(true);
        emitter.setStartSize(START_PARTICLE_SIZE);
        emitter.setEndSize(END_PARTICLE_SIZE);
        emitter.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));
        emitter.setParticlesPerSec(0);
        emitter.setGravity(0, -5f, 0);
        emitter.setLowLife(.4f);
        emitter.setHighLife(.5f);
        emitter.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 7, 0));
        emitter.getParticleInfluencer().setVelocityVariation(1.0f);
        emitter.setImagesX(2);
        emitter.setImagesY(2);
        emitter.setMaterial(material);
    }

    @Override
    public void setPhysicsSpace(PhysicsSpace space) {
        super.setPhysicsSpace(space);
        if (notNull(space)) {
            space.addCollisionListener(this);
        }
    }
    
    @Override
    public void collision(PhysicsCollisionEvent event) {
        if (isNull(this.space)) {
            return;
        }
        if (event.getObjectA() == (this) || event.getObjectB() == (this)) {
            space.add(physicsGhostObject);
            physicsGhostObject.setPhysicsLocation(getPhysicsLocation(location));
            space.addTickListener(this);
            
            if (notNull(emitter) && notNull(spatial.getParent())) {
                currentTime = 0;
                emitter.setLocalTranslation(spatial.getLocalTranslation());
                spatial.getParent().attachChild(emitter);
                emitter.emitAllParticles();
            }
            space.remove(this);
            spatial.removeFromParent();
        }
    }

    @Override
    public void prePhysicsTick(PhysicsSpace space, float tpf) {
        space.removeCollisionListener(this);
    }

    @Override
    public void physicsTick(PhysicsSpace space, float tpf) {
        Iterator<PhysicsCollisionObject> iterator = physicsGhostObject.getOverlappingObjects().iterator();
        
        while(iterator.hasNext()) {
            PhysicsCollisionObject collisionObject = iterator.next();
            if (collisionObject instanceof PhysicsRigidBody) {
                PhysicsRigidBody rigidBody = (PhysicsRigidBody)collisionObject;
                
                Vector3f currentLocation = new Vector3f();
                rigidBody.getPhysicsLocation(currentLocation);
                currentLocation.subtractLocal(location);
                
                float force = EXPLOSION_RADIUS - currentLocation.length();
                force *= FORCE_FACTOR;
                if (force < 0) {
                    force = 0;
                }
                currentLocation.normalize();
                currentLocation.multLocal(force);
                rigidBody.applyImpulse(currentLocation, Vector3f.ZERO);
            }
        }
        space.removeTickListener(this);
        space.remove(physicsGhostObject);
    }

    @Override
    public void update(float tpf) {
        super.update(tpf);
        
        if (enabled) {
            timer += tpf;
            
            if (timer > MAXIMUM_TIMER) {
                if (notNull(spatial.getParent())) {
                    space.removeCollisionListener(this);
                    space.remove(this);
                    spatial.removeFromParent();
                }
            }
            
            if (currentTime >= 0) {
                currentTime += tpf;
                if (currentTime > FIXED_TIME) {
                    currentTime = CURRENT_TIME_START;
                    emitter.removeFromParent();
                }
            }
        }
    }
}
